/*
 * Copyright (C) 2008,2009,2010  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#include "exl.h"
#include "ecodes.h"

#include <math.h>
#include <string.h>

/*
 * Prototypes
 */
static void exl(echar_t *ip);

/*
 * Initialization
 */
echar_t *stack, **hp;

/*
 * Implementation
 */
int
main(int argc, char *argv[])
{
    echar_t loop[] = { ins_jmpc, -1 };

    init_object();
    init_hash();
    init_string();
    init_stream();

    stack = malloc(4096);
    exl(loop);

    return (0);
}

#define	Sflag			0x80000000	/* sign flag */
#define	Zflag			0x00000001	/* zero flag */

static void
exl(register echar_t *ip)
{
    elong_t		 dr, sr;
    echar_t		*sp, *bp, *swp;
    eint_t	 	 fl;
    register echar_t	*d, *s;
    echar_t		*code;
    eint_t		 rc;

#ifdef GOTO_ADDRESS
#define label(name)		name
#define begin()			/**/
#define next()			goto *codes[*(euchar_t *)ip++]
#define end()			/**/
    static const void *codes[] = {
	&&ins_noop,	&&x00000001,	&&x00000010,	&&x00000011,
	&&ins_ld_dr,	&&ins_ld_sr,	&&ins_ld_bp_c,	&&ins_ld_bp_s,
	&&ins_ld_bp_i,	&&ins_ld_hp_c,	&&ins_ld_hp_s,	&&ins_ld_hp_i,
	&&x00001100,	&&x00001101,	&&__ins_ld_d,	&&ins_ld_s,
	&&ins_ld_d_c,	&&ins_ld_d_s,	&&ins_ld_d_i,	&&x00010011,
	&&ins_ld_xd_c,	&&ins_ld_xd_s,	&&ins_ld_xd_i,	&&ins_ld_xd_dr,
	&&ins_ld_xd_sr,	&&x00011001,	&&x00011010,	&&x00011011,
	&&x00011100,	&&x00011101,	&&x00011110,	&&x00011111,
	&&ins_lsc_z,	&&ins_lss_z,	&&ins_lsi_z,	&&ins_lsl_z,
	&&ins_ls_dr,	&&ins_ls_sr,	&&ins_ls_bp_c,	&&ins_ls_bp_s,
	&&ins_ls_bp_i,	&&ins_ls_hp_c,	&&ins_ls_hp_s,	&&ins_ls_hp_i,
	&&x00101100,	&&x00101101,	&&ins_ls_d,	&&__ins_ls_s,
	&&ins_ls_s_c,	&&ins_ls_s_s,	&&ins_ls_s_i,	&&x00110011,
	&&ins_ls_xs_c,	&&ins_ls_xs_s,	&&ins_ls_xs_i,	&&ins_ls_xs_dr,
	&&ins_ls_xs_sr,	&&x00111001,	&&x00111010,	&&x00111011,
	&&x00111100,	&&x00111101,	&&x00111110,	&&x00111111,
	&&ins_movc,	&&ins_movs,	&&ins_movi,	&&ins_movl,
	&&ins_addc,	&&ins_adds,	&&ins_addi,	&&ins_addl,
	&&ins_subc,	&&ins_subs,	&&ins_subi,	&&ins_subl,
	&&ins_cmpc,	&&ins_cmps,	&&ins_cmpi,	&&ins_cmpl,
	&&ins_mulc,	&&ins_muls,	&&ins_muli,	&&ins_mull,
	&&ins_divc,	&&ins_divs,	&&ins_divi,	&&ins_divl,
	&&ins_remc,	&&ins_rems,	&&ins_remi,	&&ins_reml,
	&&ins_negc,	&&ins_negs,	&&ins_negi,	&&ins_negl,
	&&ins_andc,	&&ins_ands,	&&ins_andi,	&&ins_andl,
	&&ins_orc,	&&ins_ors,	&&ins_ori,	&&ins_orl,
	&&ins_xorc,	&&ins_xors,	&&ins_xori,	&&ins_xorl,
	&&ins_shlc,	&&ins_shls,	&&ins_shli,	&&ins_shll,
	&&ins_shrc,	&&ins_shrs,	&&ins_shri,	&&ins_shrl,
	&&ins_notc,	&&ins_nots,	&&ins_noti,	&&ins_notl,
	&&ins_incc,	&&ins_incs,	&&ins_inci,	&&ins_incl,
	&&ins_decc,	&&ins_decs,	&&ins_deci,	&&ins_decl,
	&&ins_pushc,	&&ins_pushs,	&&ins_pushi,	&&ins_pushl,
	&&ins_push_d,	&&ins_push_s,	&&ins_push_bp,	&&ins_push_sp,
	&&ins_push_ip,	&&ins_push_fl,	&&ins_popc,	&&ins_pops,
	&&ins_popi,	&&ins_popl,	&&ins_pop_d,	&&ins_pop_s,
	&&ins_pop_bp,	&&ins_pop_sp,	&&ins_pop_ip,	&&ins_pop_fl,
	&&ins_pad,	&&ins_padz,	&&ins_ldrc,	&&ins_ldrs,
	&&ins_ldri,	&&ins_ldrl,	&&ins_lsrc,	&&ins_lsrs,
	&&ins_lsri,	&&ins_lsrl,	&&x10011110,	&&ins_swap_d_s,
	&&ins_jmpc,	&&ins_jmps,	&&ins_jmpa,	&&x10100011,
	&&ins_jne,	&&ins_jlt,	&&ins_jle,	&&ins_je,
	&&ins_jge,	&&ins_jgt,	&&ins_jmp_d,	&&ins_jmp_s,
	&&ins_enter,	&&ins_leave,	&&ins_calli,	&&x10101111,
	&&x10110000,	&&ins_call_s,	&&ins_ret,	&&ins_reti,
	&&x10110100,	&&ins_mcpy,	&&ins_mmov,	&&ins_mset,
	&&x10111000,	&&x10111001,	&&ins_new,	&&ins_rsz,
	&&x10111100,	&&x10111101,	&&x10111110,	&&x10111111,
	&&ins_cvt_sc,	&&ins_cvt_ic,	&&ins_cvt_lc,	&&ins_cvt_is,
	&&ins_cvt_ls,	&&ins_cvt_li,	&&ins_cvt_fl,	&&ins_cvt_dl,
	&&ins_cvt_lf,	&&ins_cvt_ld,	&&ins_cvt_fd,	&&ins_cvt_df,
	&&ins_cvt_cs,	&&ins_cvt_ci,	&&ins_cvt_cl,	&&ins_cvt_si,
	&&ins_cvt_sl,	&&ins_cvt_il,	&&x11010010,	&&x11010011,
	&&ins_fclassf,	&&ins_fclassd,	&&ins_addf,	&&ins_addd,
	&&ins_subf,	&&ins_subd,	&&ins_cmpf,	&&ins_cmpd,
	&&ins_mulf,	&&ins_muld,	&&ins_divf,	&&ins_divd,
	&&ins_remf,	&&ins_remd,	&&ins_negf,	&&ins_negd,
	&&ins_acosf,	&&ins_acosd,	&&ins_atanf,	&&ins_atand,
	&&ins_atan2f,	&&ins_atan2d,	&&ins_asinf,	&&ins_asind,
	&&ins_cbrtf,	&&ins_cbrtd,	&&ins_ceilf,	&&ins_ceild,
	&&ins_cosf,	&&ins_cosd,	&&ins_floorf,	&&ins_floord,
	&&ins_logf,	&&ins_logd,	&&ins_log10f,	&&ins_log10d,
	&&ins_powf,	&&ins_powd,	&&ins_sinf,	&&ins_sind,
	&&ins_sqrtf,	&&ins_sqrtd,	&&ins_tanf,	&&ins_tand,
    };

#else
#define label(name)		case name
#define begin()			for (;;) { switch (*(euchar_t *)ip++) {
#define next()			break
#define end()			}}
#endif

#define instruction_error()	/**/

    code = ip;
    sp = bp = stack;
    hp = null;
    fl = 0;
    dr = sr = 0;
    s = d = null;

    begin()

label(x00000001):	label(x00000010):	label(x00000011):
label(x00001100):	label(x00001101):	label(__ins_ld_d):
label(x00010011):	label(x00011001):	label(x00011010):
label(x00011011):	label(x00011100):	label(x00011101):
label(x00011110):	label(x00011111):	label(x00101100):
label(x00101101):	label(__ins_ls_s):	label(x00110011):
label(x00111001):	label(x00111010):	label(x00111011):
label(x00111100):	label(x00111101):	label(x00111110):
label(x00111111):	label(x10011110):	label(x10100011):
label(x10101111):	label(x10110000):	label(x10110100):
label(x10111000):	label(x10111001):	label(x10111100):
label(x10111101):	label(x10111110):	label(x10111111):
label(x11010010):	label(x11010011):
    instruction_error();
label(ins_noop):
    next();
label(ins_ld_dr):
    d			= (echar_t *)&dr;
    next();
label(ins_ld_sr):
    d			= (echar_t *)&sr;
    next();
label(ins_ld_bp_c):
    d			= bp + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ld_bp_s):
    d			= bp + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ld_bp_i):
    d			= bp + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ld_hp_c):
    d			= hp[*(euchar_t *)ip];
    ip			+= sizeof(echar_t);
    next();
label(ins_ld_hp_s):
    d			= hp[*(eushort_t *)ip];
    ip			+= sizeof(eshort_t);
    next();
label(ins_ld_hp_i):
    d			= hp[*(euint_t *)ip];
    ip			+= sizeof(eint_t);
    next();
label(ins_ld_s):
    d			= s;
    next();
label(ins_ld_d_c):
    d			= d + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ld_d_s):
    d			= d + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ld_d_i):
    d			= d + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ld_xd_c):
    d			= *(echar_t **)d + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ld_xd_s):
    d			= *(echar_t **)d + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ld_xd_i):
    d			= *(echar_t **)d + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ld_xd_dr):
    d			= *(echar_t **)d + dr;
    next();
label(ins_ld_xd_sr):
    d			= *(echar_t **)d + sr;
    next();
label(ins_lsc_z):
    s			= ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_lss_z):
    s			= ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_lsi_z):
    s			= ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_lsl_z):
    s			= ip;
    ip			+= sizeof(elong_t);
    next();
label(ins_ls_dr):
    s			= (echar_t *)&dr;
    next();
label(ins_ls_sr):
    s			= (echar_t *)&sr;
    next();
label(ins_ls_bp_c):
    s			= bp + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ls_bp_s):
    s			= bp + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ls_bp_i):
    s			= bp + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ls_hp_c):
    s			= hp[*(euchar_t *)ip];
    ip			+= sizeof(echar_t);
    next();
label(ins_ls_hp_s):
    s			= hp[*(eushort_t *)ip];
    ip			+= sizeof(eshort_t);
    next();
label(ins_ls_hp_i):
    s			= hp[*(euint_t *)ip];
    ip			+= sizeof(eint_t);
    next();
label(ins_ls_d):
    s			= d;
    next();
label(ins_ls_s_c):
    s			= s + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ls_s_s):
    s			= s + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ls_s_i):
    s			= s + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ls_xs_c):
    s			= *(echar_t **)s + *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ls_xs_s):
    s			= *(echar_t **)s + *(eshort_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ls_xs_i):
    s			= *(echar_t **)s + *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ls_xs_dr):
    s			= *(echar_t **)s + dr;
    next();
label(ins_ls_xs_sr):
    s			= *(echar_t **)s + sr;
    next();
label(ins_movc):
    *(echar_t *)d	= *(echar_t *)s;
    next();
label(ins_movs):
    *(eshort_t *)d	= *(eshort_t *)s;
    next();
label(ins_movi):
    *(eint_t *)d	= *(eint_t *)s;
    next();
label(ins_movl):
    *(elong_t *)d	= *(elong_t *)s;
    next();
label(ins_addc):
    *(echar_t *)d	+= *(echar_t *)s;
    next();
label(ins_adds):
    *(eshort_t *)d	+= *(eshort_t *)s;
    next();
label(ins_addi):
    *(eint_t *)d	+= *(eint_t *)s;
    next();
label(ins_addl):
    *(elong_t *)d	+= *(elong_t *)s;
    next();
label(ins_subc):
    *(echar_t *)d	-= *(echar_t *)s;
    next();
label(ins_subs):
    *(eshort_t *)d	-= *(eshort_t *)s;
    next();
label(ins_subi):
    *(eint_t *)d	-= *(eint_t *)s;
    next();
label(ins_subl):
    *(elong_t *)d	-= *(elong_t *)s;
    next();
label(ins_cmpc):
    if (*(echar_t *)d < *(echar_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(echar_t *)d > *(echar_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_cmps):
    if (*(eshort_t *)d < *(eshort_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(eshort_t *)d > *(eshort_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_cmpi):
    if (*(eint_t *)d < *(eint_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(eint_t *)d > *(eint_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_cmpl):
    if (*(elong_t *)d < *(elong_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(elong_t *)d > *(elong_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_mulc):
    *(echar_t *)d	*= *(echar_t *)s;
    next();
label(ins_muls):
    *(eshort_t *)d	*= *(eshort_t *)s;
    next();
label(ins_muli):
    *(eint_t *)d	*= *(eint_t *)s;
    next();
label(ins_mull):
    *(elong_t *)d	*= *(elong_t *)s;
    next();
label(ins_divc):
    *(echar_t *)d	/= *(echar_t *)s;
    next();
label(ins_divs):
    *(eshort_t *)d	/= *(eshort_t *)s;
    next();
label(ins_divi):
    *(eint_t *)d	/= *(eint_t *)s;
    next();
label(ins_divl):
    *(elong_t *)d	/= *(elong_t *)s;
    next();
label(ins_remc):
    *(echar_t *)d	%= *(echar_t *)s;
    next();
label(ins_rems):
    *(eshort_t *)d	%= *(eshort_t *)s;
    next();
label(ins_remi):
    *(eint_t *)d	%= *(eint_t *)s;
    next();
label(ins_reml):
    *(elong_t *)d	%= *(elong_t *)s;
    next();
label(ins_negc):
    *(echar_t *)d	= -*(echar_t *)d;
    next();
label(ins_negs):
    *(eshort_t *)d	= -*(eshort_t *)d;
    next();
label(ins_negi):
    *(eint_t *)d	= -*(eint_t *)d;
    next();
label(ins_negl):
    *(elong_t *)d	= -*(elong_t *)d;
    next();
label(ins_andc):
    *(echar_t *)d	&= *(echar_t *)s;
    next();
label(ins_ands):
    *(eshort_t *)d	&= *(eshort_t *)s;
    next();
label(ins_andi):
    *(eint_t *)d	&= *(eint_t *)s;
    next();
label(ins_andl):
    *(elong_t *)d	&= *(elong_t *)s;
    next();
label(ins_orc):
    *(echar_t *)d	|= *(echar_t *)s;
    next();
label(ins_ors):
    *(eshort_t *)d	|= *(eshort_t *)s;
    next();
label(ins_ori):
    *(eint_t *)d	|= *(eint_t *)s;
    next();
label(ins_orl):
    *(elong_t *)d	|= *(elong_t *)s;
    next();
label(ins_xorc):
    *(echar_t *)d	^= *(echar_t *)s;
    next();
label(ins_xors):
    *(eshort_t *)d	^= *(eshort_t *)s;
    next();
label(ins_xori):
    *(eint_t *)d	^= *(eint_t *)s;
    next();
label(ins_xorl):
    *(elong_t *)d	^= *(elong_t *)s;
    next();
label(ins_shlc):
    *(echar_t *)d	<<= *(euchar_t *)s;
    next();
label(ins_shls):
    *(eshort_t *)d	<<= *(euchar_t *)s;
    next();
label(ins_shli):
    *(eint_t *)d	<<= *(euchar_t *)s;
    next();
label(ins_shll):
    *(elong_t *)d	<<= *(euchar_t *)s;
    next();
label(ins_shrc):
    *(echar_t *)d	>>= *(euchar_t *)s;
    next();
label(ins_shrs):
    *(eshort_t *)d	>>= *(euchar_t *)s;
    next();
label(ins_shri):
    *(eint_t *)d	>>= *(euchar_t *)s;
    next();
label(ins_shrl):
    *(elong_t *)d	>>= *(euchar_t *)s;
    next();
label(ins_notc):
    *(echar_t *)d	= ~*(echar_t *)d;
    next();
label(ins_nots):
    *(eshort_t *)d	= ~*(eshort_t *)d;
    next();
label(ins_noti):
    *(eint_t *)d	= ~*(eint_t *)d;
    next();
label(ins_notl):
    *(elong_t *)d	= ~*(elong_t *)d;
    next();
label(ins_incc):
    ++*(echar_t *)d;
    next();
label(ins_incs):
    ++*(eshort_t *)d;
    next();
label(ins_inci):
    ++*(eint_t *)d;
    next();
label(ins_incl):
    ++*(elong_t *)d;
    next();
label(ins_decc):
    --*(echar_t *)d;
    next();
label(ins_decs):
    --*(eshort_t *)d;
    next();
label(ins_deci):
    --*(eint_t *)d;
    next();
label(ins_decl):
    --*(elong_t *)d;
    next();
label(ins_pushc):
    *(echar_t *)sp	= *(echar_t *)s;
    sp			+= sizeof(echar_t);
    next();
label(ins_pushs):
    *(eshort_t *)sp	= *(eshort_t *)s;
    sp			+= sizeof(eshort_t);
    next();
label(ins_pushi):
    *(eint_t *)sp	= *(eint_t *)s;
    sp			+= sizeof(eint_t);
    next();
label(ins_pushl):
    *(elong_t *)sp	= *(elong_t *)s;
    sp			+= sizeof(elong_t);
    next();
label(ins_push_d):
    *(echar_t **)sp	= (echar_t *)d;
    sp			+= sizeof(echar_t *);
    next();
label(ins_push_s):
    *(echar_t **)sp	= (echar_t *)s;
    sp			+= sizeof(echar_t *);
    next();
label(ins_push_bp):
    *(echar_t **)sp	= (echar_t *)bp;
    sp			+= sizeof(echar_t *);
    next();
label(ins_push_sp):
    *(echar_t **)sp	= (echar_t *)sp;
    sp			+= sizeof(echar_t *);
    next();
label(ins_push_ip):
    *(echar_t **)sp	= (echar_t *)ip;
    sp			+= sizeof(echar_t *);
    next();
label(ins_push_fl):
    *(eint_t *)sp	= (eint_t)fl;
    sp			+= sizeof(eint_t);
    next();
label(ins_popc):
    sp			-= sizeof(echar_t);
    *(echar_t *)d	= *(echar_t *)sp;
    next();
label(ins_pops):
    sp			-= sizeof(eshort_t);
    *(eshort_t *)d	= *(eshort_t *)sp;
    next();
label(ins_popi):
    sp			-= sizeof(eint_t);
    *(eint_t *)d	= *(eint_t *)sp;
    next();
label(ins_popl):
    sp			-= sizeof(elong_t);
    *(elong_t *)d	= *(elong_t *)sp;
    next();
label(ins_pop_d):
    sp			-= sizeof(echar_t *);
    d			= *(echar_t **)sp;
    next();
label(ins_pop_s):
    sp			-= sizeof(echar_t *);
    s			= *(echar_t **)sp;
    next();
label(ins_pop_bp):
    sp			-= sizeof(echar_t *);
    bp			= *(echar_t **)sp;
    next();
label(ins_pop_sp):
    sp			-= sizeof(echar_t *);
    sp			= *(echar_t **)sp;
    next();
label(ins_pop_ip):
    sp			-= sizeof(echar_t *);
    ip			= *(echar_t **)sp;
    next();
label(ins_pop_fl):
    sp			-= sizeof(eint_t);
    fl			= *(eint_t *)sp;
    next();
label(ins_pad):
    sp			+= *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_padz):
    if (*(echar_t *)ip > 0)
	memset(sp, 0, *(echar_t *)ip);
    sp			+= *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ldrc):
    *(echar_t *)&dr	= *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_ldrs):
    *(eshort_t *)&dr	= *(echar_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_ldri):
    *(eint_t *)&dr	= *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_ldrl):
    dr			= *(elong_t *)ip;
    ip			+= sizeof(elong_t);
    next();
label(ins_lsrc):
    *(echar_t *)&sr	= *(echar_t *)ip;
    ip			+= sizeof(echar_t);
    next();
label(ins_lsrs):
    *(eshort_t *)&sr	= *(echar_t *)ip;
    ip			+= sizeof(eshort_t);
    next();
label(ins_lsri):
    *(eint_t *)&sr	= *(eint_t *)ip;
    ip			+= sizeof(eint_t);
    next();
label(ins_lsrl):
    sr			= *(elong_t *)ip;
    ip			+= sizeof(elong_t);
    next();
label(ins_swap_d_s):
    swp			= d;
    d			= s;
    s			= swp;
    next();
label(ins_mcpy):
    memcpy(d, s, dr);
    next();
label(ins_mmov):
    memmove(d, s, dr);
    next();
label(ins_mset):
    memset(d, (int)dr, *(eword_t *)s);
    next();
label(ins_jmpc):
    ip			+= *(echar_t *)ip;
    next();
label(ins_jmps):
    ip			+= *(eshort_t *)ip;
    next();
label(ins_jmpa):
    ip			= code + *(eint_t *)ip;
    next();
label(ins_jne):
    if (!(fl & Zflag))
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_jlt):
    if (fl & Sflag)
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_jle):
    if (fl & (Zflag | Sflag))
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_je):
    if (fl & Zflag)
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_jge):
    if (!(fl & Sflag))
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_jgt):
    if (!(fl & (Zflag | Sflag)))
	ip		+= *(echar_t *)ip;
    else
	ip		+= sizeof(echar_t);
    next();
label(ins_jmp_d):
    ip			= d;
    next();
label(ins_jmp_s):
    ip			= s;
    next();
label(ins_enter):
    *(echar_t **)sp	= bp;
    bp			= sp;
    sp			+= sizeof(echar_t *);
    next();
label(ins_leave):
    sp			= *(echar_t **)bp;
    bp			= *(echar_t **)sp;
    next();
label(ins_calli):
    *(echar_t **)sp	= ip + sizeof(eint_t);
    sp			+= sizeof(echar_t *);
    ip			= code + *(eint_t *)ip;
    next();
label(ins_call_s):
    *(echar_t **)sp	= ip + sizeof(echar_t);
    sp			+= sizeof(echar_t *);
    ip			= s;
    next();
label(ins_ret):
    sp			-= sizeof(echar_t *);
    ip			= *(echar_t **)sp;
    next();
label(ins_reti):
    rc			= *(eint_t *)ip;
    sp			-= sizeof(echar_t *);
    ip			= *(echar_t **)sp;
    sp			-= rc;
    next();
label(ins_new):
    /* FIXME need type (probably immediate patched in the code) */
    d			= enew_object(0, *(eint_t *)s);
    next();
label(ins_rsz):
    /* FIXME define parameters */
    d			= eresize_object(d, *(eint_t *)s);
    next();
label(ins_cvt_sc):
    *(eshort_t *)d	= *(echar_t *)s;
    next();
label(ins_cvt_ic):
    *(eint_t *)d	= *(echar_t *)s;
    next();
label(ins_cvt_is):
    *(eint_t *)d	= *(eshort_t *)s;
    next();
label(ins_cvt_lc):
    *(elong_t *)d	= *(echar_t *)s;
    next();
label(ins_cvt_ls):
    *(elong_t *)d	= *(eshort_t *)s;
    next();
label(ins_cvt_li):
    *(elong_t *)d	= *(eint_t *)s;
    next();
label(ins_cvt_fl):
    *(efloat_t *)d	= *(elong_t *)s;
    next();
label(ins_cvt_dl):
    *(edouble_t *)d	= *(elong_t *)s;
    next();
label(ins_cvt_lf):
    *(elong_t *)d	= *(efloat_t *)s;
    next();
label(ins_cvt_ld):
    *(elong_t *)d	= *(edouble_t *)s;
    next();
label(ins_cvt_fd):
    *(efloat_t *)d	= *(edouble_t *)s;
    next();
label(ins_cvt_df):
    *(edouble_t *)d	= *(efloat_t *)s;
    next();
label(ins_cvt_cs):
    *(echar_t *)d	= *(eshort_t *)s;
    next();
label(ins_cvt_ci):
    *(echar_t *)d	= *(eint_t *)s;
    next();
label(ins_cvt_cl):
    *(echar_t *)d	= *(elong_t *)s;
    next();
label(ins_cvt_si):
    *(eshort_t *)d	= *(eint_t *)s;
    next();
label(ins_cvt_sl):
    *(eshort_t *)d	= *(elong_t *)s;
    next();
label(ins_cvt_il):
    *(eint_t *)d	= *(elong_t *)s;
    next();
label(ins_fclassf):
    *(eint_t *)d	= fpclassify(*(efloat_t *)s);
    next();
label(ins_fclassd):
    *(eint_t *)d	= fpclassify(*(edouble_t *)s);
    next();
label(ins_addf):
    *(efloat_t *)d	+= *(efloat_t *)s;
    next();
label(ins_addd):
    *(edouble_t *)d	+= *(edouble_t *)s;
    next();
label(ins_subf):
    *(efloat_t *)d	-= *(efloat_t *)s;
    next();
label(ins_subd):
    *(edouble_t *)d	-= *(edouble_t *)s;
    next();
label(ins_cmpf):
    if (*(efloat_t *)d < *(efloat_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(efloat_t *)d > *(efloat_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_cmpd):
    if (*(edouble_t *)d < *(edouble_t *)s)
	fl		= (fl & ~Zflag) | Sflag;
    else if (*(edouble_t *)d > *(edouble_t *)s)
	fl		&= ~(Zflag | Sflag);
    else
	fl		= (fl & ~Sflag) | Zflag;
    next();
label(ins_mulf):
    *(efloat_t *)d	*= *(efloat_t *)s;
    next();
label(ins_muld):
    *(edouble_t *)d	*= *(edouble_t *)s;
    next();
label(ins_divf):
    *(efloat_t *)d	/= *(efloat_t *)s;
    next();
label(ins_divd):
    *(edouble_t *)d	/= *(edouble_t *)s;
    next();
label(ins_remf):
    *(efloat_t *)d	= fmodf(*(efloat_t *)d, *(efloat_t *)s);
    next();
label(ins_remd):
    *(edouble_t *)d	= fmod(*(edouble_t *)d, *(edouble_t *)s);
    next();
label(ins_negf):
    *(efloat_t *)d	= -*(efloat_t *)d;
    next();
label(ins_negd):
    *(edouble_t *)d	= -*(edouble_t *)d;
    next();
label(ins_acosf):
    *(efloat_t *)d	= acosf(*(efloat_t *)d);
    next();
label(ins_acosd):
    *(edouble_t *)d	= acos(*(edouble_t *)d);
    next();
label(ins_atanf):
    *(efloat_t *)d	= atanf(*(efloat_t *)d);
    next();
label(ins_atand):
    *(edouble_t *)d	= atan(*(edouble_t *)d);
    next();
label(ins_atan2f):
    *(efloat_t *)d	= atan2f(*(efloat_t *)d, *(efloat_t *)s);
    next();
label(ins_atan2d):
    *(edouble_t *)d	= atan2(*(edouble_t *)d, *(edouble_t *)s);
    next();
label(ins_asinf):
    *(efloat_t *)d	= asinf(*(efloat_t *)d);
    next();
label(ins_asind):
    *(edouble_t *)d	= asin(*(edouble_t *)d);
    next();
label(ins_cbrtf):
    *(efloat_t *)d	= cbrtf(*(efloat_t *)d);
    next();
label(ins_cbrtd):
    *(edouble_t *)d	= cbrt(*(edouble_t *)d);
    next();
label(ins_ceilf):
    *(efloat_t *)d	= ceilf(*(efloat_t *)d);
    next();
label(ins_ceild):
    *(edouble_t *)d	= ceil(*(edouble_t *)d);
    next();
label(ins_cosf):
    *(efloat_t *)d	= cosf(*(efloat_t *)d);
    next();
label(ins_cosd):
    *(edouble_t *)d	= cos(*(edouble_t *)d);
    next();
label(ins_floorf):
    *(efloat_t *)d	= floorf(*(efloat_t *)d);
    next();
label(ins_floord):
    *(edouble_t *)d	= floor(*(edouble_t *)d);
    next();
label(ins_logf):
    *(efloat_t *)d	= logf(*(efloat_t *)d);
    next();
label(ins_logd):
    *(edouble_t *)d	= log(*(edouble_t *)d);
    next();
label(ins_log10f):
    *(efloat_t *)d	= log10f(*(efloat_t *)d);
    next();
label(ins_log10d):
    *(edouble_t *)d	= log10(*(edouble_t *)d);
    next();
label(ins_powf):
    *(efloat_t *)d	= powf(*(efloat_t *)d, *(efloat_t *)s);
    next();
label(ins_powd):
    *(edouble_t *)d	= pow(*(edouble_t *)d, *(edouble_t *)s);
    next();
label(ins_sinf):
    *(efloat_t *)d	= sinf(*(efloat_t *)d);
    next();
label(ins_sind):
    *(edouble_t *)d	= sin(*(edouble_t *)d);
    next();
label(ins_sqrtf):
    *(efloat_t *)d	= sqrtf(*(efloat_t *)d);
    next();
label(ins_sqrtd):
    *(edouble_t *)d	= sqrt(*(edouble_t *)d);
    next();
label(ins_tanf):
    *(efloat_t *)d	= tanf(*(efloat_t *)d);
    next();
label(ins_tand):
    *(edouble_t *)d	= tan(*(edouble_t *)d);
    next();

    end()
}
